In [2]:
import sys
sys.path.append('/mnt/labshare/Programs/python/HelperFunctions/')

from os import path, listdir

from scipy.constants import c, epsilon_0, mu_0
from scipy.special import ellipk, ellipkm1
from numpy import *

from IPython.display import Image
%pylab inline
pylab.rcParams['figure.figsize'] = (12, 9)
pylab.rcParams['font.size'] = 22
from scipy.constants import epsilon_0, h, hbar, e, pi
from scipy.special import ellipk

import plotly.plotly as py
from plotly.tools import mpl_to_plotly
from plotly.offline import init_notebook_mode, iplot_mpl, iplot

from plotlylayouts import *
init_notebook_mode()
Populating the interactive namespace from numpy and matplotlib
In [3]:
import pandas as pd
import re
from os import path, listdir
simdatapath = '/mnt/labshare/Chip Design/JPMQubitV3/Q3D Simulations'
listdir(simdatapath)
Out[3]:
['2D Capacitive Coupling.csv',
 '2D Coplanar Coupling.csv',
 'Distance Sweep_Result.csv',
 'GroundMeshSweep_Profile1.csv',
 'image.jpg',
 'Length Sweep d_10um_Result.csv',
 'Length Sweep d_20um_Result.csv',
 'Thickness Sweep_Result.csv',
 'TMon-CPW-Coupling.csv',
 'XMon_LSweep.csv']

Constant Definition

In [4]:
e0 = 1
e1 = 11.6
In [5]:
class cpw:
    def __init__(self, w=10., s=6., t=.1, h=500., l=1000., e1=11.6, material="nb", tgdelta=1e-8):
        self.w = w*1e-6
        self.s = s*1e-6
        self.t = t*1e-6
        self.h = h*1e-6
        self.l = l*1e-6
        self.e1 = e1
        self.tgdelta = tgdelta
        self.material = material
        
        if material == "al":
            self.Tc = 1.23
            self.rho = 4e-9
        elif material == 'nb':
            self.Tc = 8
            self.rho = 4e-9
        
        self.l0 = 1.05e-3*sqrt(self.rho/self.Tc)
    
#     Effective Dielectric Constant from Silicon-Air Interface
    
    def k0(self):
        return self.w/(self.w+2*self.s)
    
    def kp0(self):
        return sqrt(1-self.k0()**2)
    
    def k1(self):
        return sinh(pi*self.w/(4*self.h))/sinh(pi*(2*self.s+self.w)/(4*self.h))
    
    def kp1(self):
        return sqrt(1-self.k1()**2)
    
    def Eeff(self):
        return 1 + ((self.e1-1)*ellipk(self.k1())*ellipk(self.kp0()))/(2*ellipk(self.kp1())*ellipk(self.k0()))
    
#     Kinetic Inductance Calculation

    def g(self):
        a = -log(self.t/(4*self.w))
        b = -self.w/(self.w+2*self.s)*log(self.t/(4*(self.w+2*self.s)))
        c = 2*(self.w+self.s)/(self.w+2*self.s)*log(self.s/(self.w+self.s))
        return 1/(1*self.k0()**2*ellipk(self.k0())**2) * (a+b+c)
    
    def Llk(self):
        return mu_0*self.l0**2/(self.w*self.t)*self.g()
    
#     Circuit Parameters
    
    def Ll(self):
        return mu_0*ellipk(self.kp0())/(4*ellipk(self.k0())) + self.Llk()
    
    def Cl(self):
        return 4*epsilon_0*self.Eeff()*ellipk(self.k0())/ellipk(self.kp0())
    
    def vph(self):
        return 1/sqrt(self.Ll()*self.Cl())
    
    def f0(self):
        return c/(sqrt(self.Eeff())*2*self.l)
    
    def z0(self):
        return sqrt(self.Ll()/self.Cl())
    
#     Loss
    def k(self):
        return 2*pi*self.f0()*sqrt(self.Eeff())/c
    
    def alpha_d(self):
        return self.e1/sqrt(self.Eeff())*(self.Eeff()-1)/(self.e1-1)*self.tgdelta*self.k()/2
    
#     Circuit Parameters with Loss
    
    def L(self):
        return 2*self.Ll()*self.l/(pi**2)
    
    def C(self):
        return self.Cl()*self.l/2
    
    def R(self):
        return self.z0()/(self.alpha_d()*self.l)
    
    def Qint(self):
        return self.R()*self.C()/sqrt(self.L()*self.C())
    
    def wn(self):
        return self.Qint()/(self.R()*self.C())
    def fn(self):
        return self.wn()/(2*pi)
    
class resonator:
    def __init__(self, cpw, cin, cout):
        self.cpw = cpw
        self.cki = cin
        self.cko = cout
        
    def Rin(self):
        # Effective input resistance to ground
        return (1. + (self.cpw.wn()*self.cki*50.)**2)/(self.cpw.wn()*self.cki*50.)**2
    
    def Rout(self):
        # Effective output resistance to ground
        return (1. + (self.cpw.wn()*self.cko*50.)**2)/(self.cpw.wn()*self.cko*50.)**2
    
    def Cin(self):
        # Effective input capacitance to ground
        return self.cki/(1. + (self.cpw.wn()*self.cki*50.)**2)
    
    def Cout(self):
        # Effective output capacitance to ground
        return self.cko/(1. + (self.cpw.wn()*self.cko*50.)**2)
    
    def wl(self):
        # Loaded frequency in rad/s
        return 1./sqrt(self.cpw.L()*(self.cpw.C() + self.Cin() + self.Cout()))
    
    def fl(self):
        # Loaded frequency in GHz
        return self.wl()/2/pi/1e9

    def Qc(self):
        # Total coupling Q
        return self.cpw.wn() * (self.cpw.C() + self.Cin() + self.Cout())/(1./self.cpw.R() + 1./self.Rin() + 1./self.Rout())
    
    def Ql(self):
        # Loaded Q
        return 1/(1/self.cpw.Qint() + 1/self.Qc())
    
    def kappa(self):
        # Photon loss rate
        return self.wl()/self.Ql()
    
    def __str__(self):
        return "l = {} um\nf = {} GHz\nQ = {}\nk = {} MHz".format(self.cpw.l*1e6,self.fl(), self.Ql(), self.kappa()/2e6/pi)

Capacitive Coupling

Here we investigate using coplanar capacitors with a continuous ground plane in between.

In [6]:
Image('Coupling Cap.png')
Out[6]:

In the following analysis, $xt$ represents the thickness of the capacitor electrodes, and $yt$ represents the length/overlap of the electrodes.

Coupling Capacitance Simulation

Simulating the above capacitor in Q3D, we get the following results.

This is with a 2$\mu m$ ground plane in between the electrodes.

In [7]:
df = pd.read_csv(path.join(simdatapath, '2D Capacitive Coupling.csv'))
strip = lambda x: float(x[:-2])

for i, col in enumerate(df.keys()):
    if re.search('[a-zA-Z]+', str(df[col][0])):
        unit = re.findall("[a-zA-Z]+", df[col][0])[0]
        print("Column {} has units {}, Stripping...".format(i, unit))
        df[col] = df[col].apply(strip)
        df.rename(columns={col: col + ":" + unit}, inplace=True)
        
layout, trace = HeatmapPlot(title="Resonator Capacitance (fF)")
trace['x'] = df['xt:um'];layout['xaxis']['title'] = "xt (um)"
trace['y'] = df['yt:um'];layout['yaxis']['title'] = "yt (um)"
trace['z'] = df['Cr: Freq(1GHz): Original:pF']*1e3

iplot(Figure(data=[trace], layout=layout))
Column 1 has units um, Stripping...
Column 2 has units um, Stripping...
Column 3 has units pF, Stripping...

Loaded Quality Factor

Here we look at the resonator quality vs. input and output coupling capacitors.

An $R_l=50\Omega$ load coupled to a cavity with capacitance $C_k$ can be modelled as an effective capacitance $C^*$ and resistance $R^*$ to ground using the following equations:

$$ C^* = \frac{C_k}{1 + \omega_n^2C_k^2R_l^2} $$$$ R^* = \frac{1+\omega_n^2C_k^2R_l^2}{\omega_n^2C_k^2R_l} $$

For an asymmetric coupling ($C_i \neq C_o$), the coupling $Q_c$ and loaded frequency $\omega_n^*$ are given by

$$ Q_c = \omega_n^*\frac{C + C_i^* + C_o^*}{1/R + 1/R_i^* + 1/R_o^*} $$$$ \omega_n^* = \frac{1}{\sqrt{L_n(C + C_i^* + C_o^*)}} $$
In [8]:
## Example of loading effect

l = 11840. #um

line = cpw(l=l)

print("Length: {} um".format(l))
print("Unloaded Frequency: {} GHz".format(line.fn()/1e9))

cin = 5e-15 #F
cout= 5e-15 #F

res = resonator(line, cin, cout)
print("Coupling quality factor: {}".format(res.Qc()))
print("Loaded Q: {}".format(res.Ql()))
print("Loaded frequency: {} GHZ".format(res.fl()))

print(res)
Length: 11840.0 um
Unloaded Frequency: 5.000057458236854 GHz
Coupling quality factor: 243.54656321473004
Loaded Q: 243.54519266106033
Loaded frequency: 4.9738493675415505 GHZ
l = 11840.0 um
f = 4.9738493675415505 GHz
Q = 243.54519266106033
k = 20.422695735421936 MHz
In [10]:
Cout = linspace(1, 20, 101)*1e-15 # F

l = 11840 #um
line = cpw(l=l) #CPW Length
cin = 1e-15 # F

kappas = []
freqs = []

for cout in Cout:
    kappas.append(resonator(line, cin, cout).kappa()/2e6/pi) #Find kappa in MHz
    freqs.append(resonator(line, cin, cout).fl())

layout, trace = LinePlot(title="Linewidth vs. output capacitance", x=Cout*1e15, y=kappas)
layout['xaxis'].update(title='Output Capacitance (fF)')
layout['yaxis'].update(title='Kappa (MHz)')
iplot(Figure(data=[trace], layout=layout))

layout, trace = LinePlot(title="Frequency vs. output capacitance", x=Cout*1e15, y=freqs)
layout['xaxis'].update(title='Output Capacitance (fF)')
layout['yaxis'].update(title='Resonant Frequency (GHz)')
iplot(Figure(data=[trace], layout=layout))
In [9]:
 
Out[9]:
'/home/cjhowing/.jupyter\\custom'
In [ ]: